package com.huawei.util;

import java.sql.*;

/**
 * 数据库操作工具类（优化版）
 * ✅ 自动资源管理
 * ✅ 更安全的异常处理
 * ✅ 支持回调式查询（避免 ResultSet 泄漏）
 */
public class DBManagerPerfAI {

    // ✅ JDBC 4+ 会自动加载驱动，Class.forName 可省略（保留也无害）
    static {
        try {
            Class.forName("org.postgresql.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("PostgreSQL 驱动未找到，请检查依赖", e);
        }
    }

    /**
     * 创建数据库连接
     */
    public static Connection openConnection(String url, String username, String password) {
        // ✅ 使用更合适的异常类型
        if (url == null || url.trim().isEmpty()) {
            throw new IllegalArgumentException("数据库URL不能为空");
        }
        if (username == null || username.trim().isEmpty()) {
            throw new IllegalArgumentException("数据库用户名不能为空");
        }
        if (password == null) {
            throw new IllegalArgumentException("数据库密码不能为空");
        }

        try {
            return DriverManager.getConnection(url.trim(), username.trim(), password.trim());
        } catch (SQLException e) {
            throw new RuntimeException("数据库连接失败: " + e.getMessage(), e);
        }
    }

    /**
     * 安全关闭连接（静默处理异常）
     */
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                if (!conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                // ✅ 日志记录（生产环境应使用 SLF4J）
                System.err.println("关闭数据库连接失败: " + e.getMessage());
            }
        }
    }

    /**
     * ✅ 推荐：回调式查询（自动管理资源，避免 ResultSet/Statement 泄漏）
     * 示例：
     *   List<User> users = DBManagerPerf.executeQuery(conn, "SELECT id, name FROM users WHERE age > ?",
     *       rs -> {
     *           List<User> list = new ArrayList<>();
     *           while (rs.next()) {
     *               list.add(new User(rs.getLong("id"), rs.getString("name")));
     *           }
     *           return list;
     *       },
     *       18);
     */
    @FunctionalInterface
    public interface ResultSetHandler<T> {
        T handle(ResultSet rs) throws SQLException;
    }

    public static <T> T executeQuery(Connection conn, String sql, ResultSetHandler<T> handler, Object... params) throws SQLException {
        if (conn == null || conn.isClosed()) {
            throw new SQLException("数据库连接无效");
        }
        // ✅ 使用 try-with-resources 自动关闭 PreparedStatement 和 ResultSet
        try (PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
            setParameters(ps, params);
            try (ResultSet rs = ps.executeQuery()) {
                return handler.handle(rs);
            }
        }
    }

    /**
     * 执行更新操作（INSERT/UPDATE/DELETE）
     */
    public static int executeUpdate(Connection conn, String sql, Object... params) throws SQLException {
        if (conn == null || conn.isClosed()) {
            throw new SQLException("数据库连接无效");
        }
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            setParameters(ps, params);
            return ps.executeUpdate();
        }
    }

    /**
     * 设置 PreparedStatement 参数
     */
    private static void setParameters(PreparedStatement ps, Object[] params) throws SQLException {
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
        }
    }

    // ========== 以下为兼容旧代码的保留方法（不推荐使用） ==========

    /**
     * ⚠️ 不推荐：返回 ResultSet 需手动关闭，极易资源泄漏
     */
    @Deprecated
    public static ResultSet query(Connection conn, String sql, Object[] obs) throws SQLException {
        if (conn == null || conn.isClosed()) {
            throw new SQLException("数据库连接无效");
        }
        PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setParameters(ps, obs);
        return ps.executeQuery(); // ⚠️ 调用方必须关闭 ps 和 rs！
    }

    @Deprecated
    public static int update(Connection conn, String sql, Object... obs) throws SQLException {
        return executeUpdate(conn, sql, obs);
    }
}